#!/usr/bin/env python
def eval_expression(elements, name, operator, arg, ui):
#    print "Evaluating %s.%s(%r)" % (name,operator,arg)
    ## Try and find the element with the specified name:
    element = None
    for e in elements:
        if e.name == name:
            element = e
            break
    
    if not element:
        raise RuntimeError("Column %s not known" % name)

    ## Use the element to parse:
    return element.parse(name, operator, arg, context='code', ui=ui)

def logical_operator_parse(left, operator, right):
    if operator=="and":
        return lambda row: left(row) and right(row)
    elif operator=="or":
        return lambda row: left(row) or right(row)

    raise RuntimeError("operator %s not supported" % operator)


# Begin -- grammar generated by Yapps
import sys, re
from yapps import runtime

class CodeParserScanner(runtime.Scanner):
    patterns = [
        ("'\\\\)'", re.compile('\\)')),
        ("'\\\\('", re.compile('\\(')),
        ('[ \r\t\n]+', re.compile('[ \r\t\n]+')),
        ('END', re.compile('$')),
        ('STR', re.compile('"([^\\\\"]+|\\\\.)*"')),
        ('STR2', re.compile("'([^\\\\']+|\\\\.)*'")),
        ('WORD', re.compile('[-:+*/!@$%^&=\\<\\>.a-zA-Z0-9_]+')),
        ('LOGICAL_OPERATOR', re.compile('(and|or|AND|OR)')),
    ]
    def __init__(self, str,*args,**kw):
        runtime.Scanner.__init__(self,None,{'[ \r\t\n]+':None,},str,*args,**kw)

class CodeParser(runtime.Parser):
    Context = runtime.Context
    def goal(self, types, ui, _parent=None):
        _context = self.Context(_parent, self._scanner, 'goal', [types, ui])
        clause = self.clause(types, ui, _context)
        END = self._scan('END', context=_context)
        return clause

    def clause(self, types, ui, _parent=None):
        _context = self.Context(_parent, self._scanner, 'clause', [types, ui])
        expr = self.expr(types, ui, _context)
        result = expr
        while self._peek('LOGICAL_OPERATOR', 'END', "'\\\\)'", context=_context) == 'LOGICAL_OPERATOR':
            LOGICAL_OPERATOR = self._scan('LOGICAL_OPERATOR', context=_context)
            logical_operator = LOGICAL_OPERATOR
            expr = self.expr(types, ui, _context)
            result = logical_operator_parse(result, logical_operator, expr)
        return result

    def term(self, _parent=None):
        _context = self.Context(_parent, self._scanner, 'term', [])
        _token = self._peek('STR', 'STR2', 'WORD', context=_context)
        if _token == 'STR':
            STR = self._scan('STR', context=_context)
            return eval(STR)
        elif _token == 'STR2':
            STR2 = self._scan('STR2', context=_context)
            return eval(STR2)
        else: # == 'WORD'
            WORD = self._scan('WORD', context=_context)
            return WORD

    def expr(self, types, ui, _parent=None):
        _context = self.Context(_parent, self._scanner, 'expr', [types, ui])
        _token = self._peek('STR', 'STR2', 'WORD', "'\\\\('", context=_context)
        if _token != "'\\\\('":
            term = self.term(_context)
            column = term
            WORD = self._scan('WORD', context=_context)
            operator = WORD
            term = self.term(_context)
            return  eval_expression(types, column,operator,term, ui)
        else: # == "'\\\\('"
            self._scan("'\\\\('", context=_context)
            clause = self.clause(types, ui, _context)
            self._scan("'\\\\)'", context=_context)
            return  clause


def parse(rule, text):
    P = CodeParser(CodeParserScanner(text))
    return runtime.wrap_error_reporter(P, rule)

# End -- grammar generated by Yapps



def parse_eval(text, types, ui):
    """ This return a parse tree from the expression in text using the
    table objects in types.

    A parse tree is essentially a function which may be called with:
    function(row)

    where row is a dict containing all the column in the row. The
    function returns True if the filter expression applies to the row
    or False otherwise.

    Note that once the filter is parsed there is no need to re-parse
    it for each row, just reuse the function over and over. This is
    very fast.
    """
    P = CodeParser(CodeParserScanner(text))
    try:
        return P.goal(types, ui)
    except runtime.SyntaxError, e:
        raise RuntimeError("\n%s\n%s^\n%s" % (text, '-' * e.pos[2], e.msg))


if __name__=='__main__':
    import pyflag.TableObj as TableObj
    
    types = [ TableObj.TimestampType(name='Timestamp'),
              TableObj.IPType(name='IP Address')]

    test = 'Timestamp < "2006-10-01 \\\"10:10:00\\\"" or (Timestamp before \'2006-11-01 "10:10:00"\' and  "IP Address" netmask "10.10.10.0/24") or "IP Address" = 192.168.1.1'
    print "Will test %s" % test
    print parse_eval(test,types)
